package json2xml;

// using string template to translate json to xml

/*
 translate from
 {
  "description" : "An imaginary server config file",
  "logs" : {"level":"verbose", "dir":"/var/log"},
  "host" : "antlr.org",
  "admin": ["parrt", "tombu"],
  "aliases": []
}

to

<description>An imaginary server config file</description>
<logs>
<level>verbose</level>
<dir>/var/log</dir>
</logs>
<host>antlr.org</host>
<admin>
<element>parrt</element>
<element>tombu</element>
</admin>
<aliases></aliases>

*/

import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeProperty;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
import org.stringtemplate.v4.STGroupFile;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Paths;

public class JSON2XMLSt {
    public static class XMLEmitter extends JSONBaseListener {
        ParseTreeProperty<ST> xml = new ParseTreeProperty<>();
        // source code file location
        // Test.class.getProtectionDomain().getCodeSource().getLocation()

        // file location
        // Paths.get(".").toAbsolutePath().normalize().toString();
        STGroup templates = new STGroupFile(        Paths.get(".").toAbsolutePath().normalize().toString()+"/src/main/java/json2xml/XML.stg");

        public void exitJson(JSONParser.JsonContext context) {
            xml.put(context, xml.get(context.getChild(0)));
        }

        public void exitEmptyObject(JSONParser.EmptyObjectContext context) {
            xml.put(context, templates.getInstanceOf("empty"));
        }

        public void exitAnObject(JSONParser.AnObjectContext context) {
            ST objectST = templates.getInstanceOf("object");
            for (JSONParser.PairContext pairContext : context.pair()) {
                objectST.add("fields", xml.get(pairContext));
            }
            xml.put(context, objectST);
        }

        public void exitEmptyArray(JSONParser.EmptyArrayContext context) {
            xml.put(context, templates.getInstanceOf("empty"));
        }

        public void exitArrayOfValues(JSONParser.ArrayOfValuesContext context) {
            ST arrayST = templates.getInstanceOf("array");
            for (JSONParser.ValueContext valueContext : context.value()) {
                arrayST.add("values", xml.get(valueContext));
            }
            xml.put(context, arrayST);
        }

        public void exitPair(JSONParser.PairContext context) {
            String name = stripQuotes(context.STRING().getText());
            JSONParser.ValueContext valueContext = context.value();
            ST tag = templates.getInstanceOf("tag");
            tag.add("name", name);
            tag.add("content", xml.get(valueContext));
            xml.put(context, tag);
        }

        public void exitAtom(JSONParser.AtomContext context) {
            xml.put(context, value(context.start.getText()));
        }

        public void exitObjectValue(JSONParser.ObjectValueContext context) {
            xml.put(context, xml.get(context.object()));
        }

        public void exitArrayValue(JSONParser.ArrayValueContext context) {
            JSONParser.ArrayContext arrayContext = context.array();
            xml.put(context, xml.get(arrayContext));
        }

        public void exitString(JSONParser.StringContext context) {
            xml.put(context, value(stripQuotes(context.start.getText())));
        }

        public static String stripQuotes(String s) {
            if (s == null || s.charAt(0) != '"') {
                return s;
            }
            return s.substring(1, s.length()-1);
        }

        ST value(Object x) {
            ST st = templates.getInstanceOf("value");
            st.add("x", x);
            return st;
        }
    }

    public static void main(String[] args) throws IOException {
        String inputFile = null;
        if(args.length > 0) {
            inputFile = args[0];
        }
        InputStream is = System.in;
        if (inputFile != null) {
            is = new FileInputStream(inputFile);
        }
        CharStream input = CharStreams.fromStream(is);
        JSONLexer lexer = new JSONLexer(input);
        CommonTokenStream tokenStream = new CommonTokenStream(lexer);
        JSONParser parser = new JSONParser(tokenStream);
        parser.setBuildParseTree(true);
        ParseTree tree = parser.json();
        System.out.println(tree.toStringTree(parser));

        ParseTreeWalker walker = new ParseTreeWalker();
        XMLEmitter converter = new XMLEmitter();
        walker.walk(converter, tree);
        System.out.println(converter.xml.get(tree).render());
    }
}
